<template>
  <h2>智能等号程序</h2>
  <el-form label-position="right" label-width="auto">
    <el-form-item label="输入排队人数（人），用空格隔开：">
      <el-input v-model="dataX" />
    </el-form-item>
    <el-form-item label="输入等号时间（分），用空格隔开：">
      <el-input v-model="dataY" />
    </el-form-item>
  </el-form>
  <div class="btns">
    <el-button type="success" @click="useTodayDatas"> 使用今日数据 </el-button>
    <el-button type="primary" @click="initChart"> 生成散点图 </el-button>
    <el-button type="info" @click="goUrl('home')"> 返回首页 </el-button>
  </div>
  <div class="charts">
    <ScatterChart
      :scatterData="scatterData"
      :lineData="lineData"
      :lineData2="lineData2"
      :newScatter="newScatter"
    />
  </div>
  <div class="result">
    <p
      v-if="formula !== ''"
      style="display: flex; justify-content: space-between; align-items: center"
    >
      线性回归公式：{{ formula }}
      <span>
        <el-button
          type="primary"
          plain
          @click="getGuocheng"
          v-if="scatterData.length > 0"
          :disabled="isDonghuazhong"
        >
          生成过程
        </el-button>
        <span>{{ temFormula }}</span>
      </span>
    </p>
    <p v-else>
      <el-button
        type="warning"
        @click="getFormula"
        v-if="scatterData.length > 0"
      >
        生成线性回归公式
      </el-button>
    </p>
    <div class="compute">
      <div class="item">
        <el-input
          v-model="num"
          placeholder="输入排队人数（人）"
          class="input-with-btn"
        />
        <el-button type="warning" @click="getTimeByNum">预测等号时间</el-button>
        <span v-if="numTxt === ''">输入排队人数后可预测等号时间（分）</span>
        <span v-else>{{ numTxt }}</span>
      </div>
      <div class="item">
        <el-input
          v-model="time"
          placeholder="输入等号时间（分）"
          class="input-with-btn"
        />
        <el-button type="success" @click="getNumByTime">预测排队人数</el-button>
        <span v-if="timeTxt === ''">输入等号时间后可预测排队人数（人）</span>
        <span v-else>{{ timeTxt }}</span>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import { ElMessageBox, ElMessage } from "element-plus";
import ScatterChart from "@/components/ScatterChart.vue";
import { useRouter } from "vue-router";

const router = useRouter();
const dataX = ref("");
const dataY = ref("");
const formula = ref("");
const scatterData = ref([]);
const lineData = ref([
  [0, 0],
  [0, 0],
]);
const lineData2 = ref([
  [0, 0],
  [0, 0],
]);
const newScatter = ref([]);
const num = ref("");
const numTxt = ref("");
const time = ref("");
const timeTxt = ref("");
const formulaData = ref(null);
const temFormula = ref("");
const isDonghuazhong = ref(false);

// 页面加载时读取文件内容
onMounted(() => {});
const useTodayDatas = () => {
  let arrx = [1, 5, 10, 12, 15, 20, 25];
  let arry = [3, 21, 31, 35, 40, 54, 63];
  dataX.value = arrx.join(" ");
  dataY.value = arry.join(" ");
};
const goUrl = (name) => {
  router.push({ name: name });
};
const initChart = () => {
  let arrx = dataX.value.trim().split(/\s+/).map(Number);
  let arry = dataY.value.trim().split(/\s+/).map(Number);
  if (arrx.length === arry.length && dataX.value !== "") {
    scatterData.value = arrx.map((a, index) => {
      return [a, arry[index]];
    });
    lineData.value = [
      [0, 0],
      [0, 0],
    ];
    formulaData.value = null;
    formula.value = "";
    newScatter.value = [];
  } else {
    ElMessage.error("排队人数数据应于等号时间数据长度一致,且不能少于2组！");
  }
};
const getFormula = () => {
  let arrx = dataX.value.trim().split(/\s+/).map(Number);
  let arry = dataY.value.trim().split(/\s+/).map(Number);
  if (arrx.length === arry.length) {
    let { slope, intercept } = linearRegression(arrx, arry);
    formula.value = `y = ${slope.toFixed(2)}x + ${intercept.toFixed(2)}`;
    const lastX = arrx[arrx.length - 1]; // 获取数组最后一个元素
    lineData.value = [
      [0, Number(intercept).toFixed(2)],
      // [arrx[0], (slope.toFixed(2) * arrx[0] + intercept).toFixed(2)],
      [lastX, (slope.toFixed(2) * lastX + intercept).toFixed(2)],
    ];
    formulaData.value = {
      slope: slope.toFixed(2) * 1,
      intercept: intercept.toFixed(2) * 1,
    };
  }
};
const getGuocheng = () => {
  let arrx = dataX.value.trim().split(/\s+/).map(Number);
  let arry = dataY.value.trim().split(/\s+/).map(Number);

  if (arrx.length === arry.length && arrx.length > 1) {
    isDonghuazhong.value = true;
    const loop = (i, count) => {
      setTimeout(() => {
        if (count < 4) {
          // 获取当前的数据点
          let actxs = arrx.filter((_, index) => index < i);
          let actys = arry.filter((_, index) => index < i);

          // 计算线性回归
          let { slope, intercept } = linearRegression(actxs, actys);
          temFormula.value = `y = ${slope.toFixed(2)}x + ${intercept.toFixed(
            2
          )}`;

          // 获取数组最后一个元素
          const lastX = actxs[actxs.length - 1];

          // 更新 lineData2.value
          lineData2.value = [
            [actxs[0], Number((slope * actxs[0] + intercept).toFixed(2))],
            [lastX, Number((slope * lastX + intercept).toFixed(2))],
          ];
          // 判断是否需要重新开始循环
          if (i < arrx.length) {
            loop(i + 1, count); // 继续下一次迭代
          } else {
            loop(2, count + 1); // 重新从 i = 2 开始
          }
        } else {
          isDonghuazhong.value = false;
        }
      }, 1000); // 每次延迟 1 秒
    };

    // 启动循环
    loop(2, 1);
  }
};
//生成线性回归公式
function linearRegression(x, y) {
  const n = x.length;
  let sumX = 0,
    sumY = 0,
    sumXY = 0,
    sumXX = 0;

  for (let i = 0; i < n; i++) {
    sumX += x[i];
    sumY += y[i];
    sumXY += x[i] * y[i];
    sumXX += x[i] * x[i];
  }

  const slope = (n * sumXY - sumX * sumY) / (n * sumXX - sumX * sumX);
  const intercept = (sumY - slope * sumX) / n;
  return { slope, intercept };
}
function getTimeByNum() {
  if (!isNaN(parseFloat(num.value)) && isFinite(num.value)) {
    if (formulaData.value) {
      let finalTime = Math.ceil(
        formulaData.value.slope * num.value + formulaData.value.intercept
      );
      numTxt.value = "等号时间：" + finalTime + "分";
      newScatter.value.push([num.value, finalTime]);
    } else {
      ElMessageBox.alert("请先点击生成图表获取计算公式", "系统提示", {
        type: "warning",
        closeOnClickModal: true,
      });
    }
  } else {
    num.value = "";
    numTxt.value = "";
    ElMessageBox.alert("请输入正确的排队人数", "系统提示", {
      type: "warning",
      closeOnClickModal: true,
    });
  }
}
function getNumByTime() {
  if (!isNaN(parseFloat(time.value)) && isFinite(time.value)) {
    if (formulaData.value) {
      let finalNum = Math.ceil(
        (time.value - formulaData.value.intercept) / formulaData.value.slope
      );
      timeTxt.value = "排队人数：" + finalNum + "人";
      newScatter.value.push([finalNum, time.value]);
    } else {
      ElMessageBox.alert("请先点击生成图表获取计算公式", "系统提示", {
        type: "warning",
        closeOnClickModal: true,
      });
    }
  } else {
    time.value = "";
    timeTxt.value = "";
    ElMessageBox.alert("请输入正确的排队时间", "系统提示", {
      type: "warning",
      closeOnClickModal: true,
    });
  }
}
</script>

<style lang="scss" scoped>
.btns {
  display: flex;
  width: 100%;
  justify-content: space-around;
  align-items: center;
}
.charts {
  margin-top: 30px;
}
.result {
  > p {
    padding-left: 15px;
  }
  text-align: left;
  padding-bottom: 80px;
  .item {
    display: flex;
    align-items: center;
    margin-top: 10px;
  }
  :deep(.input-with-btn) {
    width: 30%;
  }
  :deep(.el-button) {
    margin: 0 15px 0 5px;
  }
}
.compute {
  background: #f0f0f0;
  padding: 15px 15px 25px;
}
</style>
